// 基于openlayers 的 绘制marker点、绘制线、弹窗的工具类
import BasicMap from './BasicMap'

const ol = window.ol

class BasicMapUtils extends BasicMap {
  /**
   * @method 绘制自定义图标的marker点
   * @param {number} x  墨卡托投影下的x
   * @param {number} y  墨卡托投影下的y
   * @param {string} icon 图标-用require('assets/images/xxx.png')这样的方式赋值
   * @returns markerPoint, markerFeature, markerLayer
   */
  createMarker({ x, y, icon, userData, anchor = [0, 0] }) {
    const markerPoint = new ol.geom.Point([x, y])
    const markerFeature = new ol.Feature({
      userData: {
        ...userData,
        type: 'marker'
      },
      geometry: markerPoint
    })
    const markerIcon = new ol.style.Style({
      image: new ol.style.Icon({
        anchor,
        src: icon
      })
    })
    markerFeature.setStyle(markerIcon)
    const markerSource = new ol.source.Vector({
      features: [markerFeature]
    })
    const markerLayer = new ol.layer.Vector({
      source: markerSource
    })
    return {
      markerPoint, // 源数据
      markerFeature, // 自定义样式
      markerLayer // 加入地图的图层
    }
  }

  /**
   * @method  绘制弹窗
   * @param {HTMLElement} htmlElemnt
   * @param {Array[x, y]} position x, y 是墨卡托投影下的x，y
   * @param {Arrat<number>} offset 偏移位置
   * @param {string} positioning 对其位置 默认下中
   * @param 参考文档： https://openlayers.org/en/latest/apidoc/module-ol_Overlay-Overlay.html
   * @returns overlay  通过 map.addOverlay(overlay)添加
   */
  createOverlay({ htmlElement, position, offset = [15, -20], positioning = 'bottom-center' }) {
    const overlay = new ol.Overlay({
      element: htmlElement,
      offset,
      positioning,
      autoPan: false,
      autoPanAnimation: {
        duration: 20
      }
    })
    if (position) {
      overlay.setPosition(position)
    }
    return overlay
  }

  /**
   * @method 绘制线段
   * @param {array} lineArr  线对应的点的数组  点需要是墨卡托投影下的x，y
   * @param {color} color 线的颜色
   * @param {number} width 线的粗细
   * @returns lineLayer 返回线的图层 通过 map.addLayer(lineLayer)添加
   */
  createLine({ lineArr, color = '#1576e2', width = 4, userData = {} }) {
    const lineGeometry = new ol.geom.LineString(lineArr)
    const lineFeature = new ol.Feature({
      userData: {
        ...userData,
        type: 'line'
      },
      geometry: lineGeometry
    })
    const source = new ol.source.Vector({
      features: [lineFeature]
    })
    const lineLayer = new ol.layer.Vector({
      source
    })
    const style = new ol.style.Style({
      stroke: new ol.style.Stroke({
        color,
        width
      })
    })
    lineFeature.setStyle(style)
    return {
      lineGeometry, // 源数据
      lineFeature, // 内置样式不满足要求时，用于自定义样式
      lineLayer // 用于加入地图
    }
  }

  /**
   * @method 绘制带方向箭头的线段-目前只用于公交线路上表示上下行
   * @param {array} lineArr  线对应的点的数组  点需要是墨卡托投影下的x，y
   * @param {color} color 线的颜色
   * @param {number} width 线的粗细
   * @returns lineLayer 返回线的图层 通过 map.addLayer(lineLayer)添加
   */
  createLineWithDirection({ lineArr, color = '#1576e2', width = 4, userData = {} }) {
    const lineGeometry = new ol.geom.LineString(lineArr)
    const lineFeature = new ol.Feature({
      userData: {
        ...userData,
        type: 'line'
      },
      geometry: lineGeometry
    })
    const source = new ol.source.Vector({
      features: [lineFeature]
    })
    const lineLayer = new ol.layer.Vector({
      source
    })
    const stylesFunction = () => {
      const resolution = this.map.getView().getResolution() // 分辨率:一个像素代表的距离
      var geometry = lineFeature.getGeometry() // 几何对象:空间坐标信息等
      var length = geometry.getLength() // 长度:线几何对象的长度
      var radio = (100 * resolution) / length // 间隔分之一 分割了多少段
      var dradio = 1 // 投影坐标系，如3857等，在EPSG:4326下可以设置dradio=10000
      // 线段样式
      var styles = [
        new ol.style.Style({
          stroke: new ol.style.Stroke({
            color,
            width
          })
        })
      ]
      // 添加箭头样式
      for (var i = 0; i <= 1; i += radio) {
        var arrowLocation = geometry.getCoordinateAt(i)
        geometry.forEachSegment(function (start, end) {
          // 暂时不考虑这种情况
          // if (start[0] === end[0] || start[1] === end[1]) return
          var dx1 = end[0] - arrowLocation[0]
          var dy1 = end[1] - arrowLocation[1]
          var dx2 = arrowLocation[0] - start[0]
          var dy2 = arrowLocation[1] - start[1]
          if (dx1 !== dx2 && dy1 !== dy2) {
            if (Math.abs(dradio * dx1 * dy2 - dradio * dx2 * dy1) < 0.001) {
              var dx = end[0] - start[0]
              var dy = end[1] - start[1]
              var rotation = Math.atan2(dy, dx) // 得到箭头方向角
              styles.push(
                new ol.style.Style({
                  geometry: new ol.geom.Point(arrowLocation),
                  image: new ol.style.Icon({
                    src: require('assets/images/road-arrow.png'),
                    anchor: [0.4, 0.5],
                    scale: 0.06,
                    rotateWithView: false,
                    color: 'white',
                    rotation: -rotation
                  })
                })
              )
            }
          }
        })
      }
      return styles
    }
    lineFeature.setStyle(stylesFunction)
    return {
      lineGeometry, // 源数据
      lineFeature, // 要是内置的样式不满足要求，用于自定义样式
      lineLayer // 用于直接加入地图
    }
  }

  /**
   * @method 创建小球运动轨迹的动画
   * @param {Object} markerLayer  要运动点的Layer
   * @param {Object} lineGeometry  运动轨迹数据
   * @param {number} speed  运动的速度
   * @param {Object} markerStyle  重绘的样式
   * @param {Object} markerFeature  点的feature
   * @param {Object} animating  是否出于运动状态的标志 true运动中
   * @param {String} id  元素的id
   */
  createMovementAnimation({ markerLayer, lineGeometry, speed = 3, markerStyle, markerFeature, animating = false, id = '' }) {
    console.log('createMovementAnimation')
    const startButton = document.getElementById(id)
    // 获取路线的坐标
    const routeCoords = lineGeometry.getCoordinates()
    const routeLength = routeCoords.length
    let lastTime = new Date().getTime()
    const moveFeature = event => {
      // 获取用于绘制到事件画布的矢量上下文
      const vectorContext = ol.render.getVectorContext(event)
      const frameState = event.frameState
      if (animating) {
        // 当animating为true的时候才执行
        const elapsedTime = frameState.time - lastTime
        // 这里提升速度的技巧时在lineString的坐标上跳过几个索引
        const index = Math.round((speed * elapsedTime) / 1000)
        // 当索引大过总数的时候就结束
        if (index >= routeLength) {
          console.log('要结束了')
          stopAnimation(true)
          return
        }
        // 把最近的一个点拿出来做成要素，形成动画效果
        const currentPoint = new ol.geom.Point(routeCoords[index])
        const feature = new ol.Feature(currentPoint)
        vectorContext.drawFeature(feature, markerStyle)
      }
      // 继续渲染动画
      this.map.render()
    }
    const stopAnimation = ended => {
      // 把aniamting设为false
      animating = false
      this.animating = false
      // 如果点击取消动画，在开始的地方设置标记
      // 如果ended为true，就把点放到最后一个；如果ended为false，就把点放第一个。
      const coord = ended ? routeCoords[routeLength - 1] : routeCoords[0]
      // 给geoMaker设为coords
      const geometry = markerFeature.getGeometry()
      geometry.setCoordinates(coord)
      // 解绑postrender事件监听
      markerLayer.un('postrender', moveFeature)
    }
    const startAnimation = () => {
      if (animating) {
        // 如果animating为true就执行停止动画的函数
        stopAnimation(false)
      } else {
        // 把animating改为true，设置时间戳，取到初始速度
        animating = true
        this.animating = true
        lastTime = new Date().getTime()
        // 隐藏标记
        markerFeature.setStyle(null)
        // this.map.removeLayer(markerLayer)
        // 防止平移了地图，重新设置地图中心
        // this.map.getView().setCenter(center)
        // 添加postrender回调
        markerLayer.on('postrender', moveFeature)
        // 渲染地图
        this.map.render()
      }
    }
    // startAnimation()
    startButton.addEventListener('click', startAnimation, false)
    // markerLayer.on('postrender', moveFeature)
  }
}

export default BasicMapUtils
